package jnpf.fico.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jnpf.base.service.IBaseSerialNumberService;
import jnpf.fico.entity.ZcBillItemEntity;
import jnpf.fico.entity.ZcBillOperateEntity;
import jnpf.fico.entity.ZcBillOperateItemEntity;
import jnpf.fico.mapper.ZcBillOperateMapper;
import jnpf.fico.model.bill.ZcBillReduceForm;
import jnpf.fico.model.bill.ZcBillReduceItemModel;
import jnpf.fico.model.bill.ZcBillRefundForm;
import jnpf.fico.model.bill.ZcBillRefundItemModel;
import jnpf.fico.model.operate.ZcBillOperateDetailVo;
import jnpf.fico.model.operate.ZcBillOperateMainVo;
import jnpf.fico.model.operate.ZcBillOperatePagination;
import jnpf.fico.service.ZcBillItemService;
import jnpf.fico.service.ZcBillOperateItemService;
import jnpf.fico.service.ZcBillOperateService;
import jnpf.util.UserProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class ZcBillOperateServiceImpl extends ServiceImpl<ZcBillOperateMapper, ZcBillOperateEntity> implements ZcBillOperateService {

    @Autowired
    private UserProvider userProvider;

    @Autowired
    private ZcBillItemService billItemService;

    @Autowired
    private ZcBillOperateItemService operateItemService;

    @Autowired
    private IBaseSerialNumberService serialNumberService;

    @Override
    public void addReduceRequest(ZcBillReduceForm form) {
        // 变更记录
        ZcBillOperateEntity entity = new ZcBillOperateEntity();
        entity.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
        // 减免账单
        entity.setParentId(form.getBillId());
        entity.setType(1);
        entity.setEventName("账单减免");

        // 生成流水号
        entity.setSerialNo(serialNumberService.getSerialNumber("D"));

        entity.setOperateDate(form.getReduceDate());
        entity.setReason(form.getReason());
        entity.setFilePath(form.getFile());

        // 获取减免费用项
        List<ZcBillReduceItemModel> reduceList = form.getReduceItem();
        if (CollUtil.isNotEmpty(reduceList)) {

            List<ZcBillOperateItemEntity> items = new ArrayList<>();
            StringBuilder contentBuilder = new StringBuilder("");
            for (ZcBillReduceItemModel item : reduceList) {
                // 获取减免费用项
                ZcBillItemEntity billItem = billItemService.getById(item.getBillItemId());
                if (billItem != null) {
                    // 设置操作费用详情
                    ZcBillOperateItemEntity operateItem = new ZcBillOperateItemEntity();
                    operateItem.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
                    operateItem.setParentId(entity.getId());
                    operateItem.setBillItemId(billItem.getId());
                    operateItem.setExpenseItem(billItem.getExpenseItem());
                    operateItem.setOrAmount(billItem.getReduceAmount());
                    operateItem.setOroAmount(billItem.getReduceOverdueAmount());

                    String tempContent = "|费用项:" + billItem.getExpenseItem();
                    // 本金减免叠加u
                    if (item.getReduceAmount() != null) {
                        // TODO 检验减免金额是否超过本金
                        tempContent = tempContent + ",减免本金：" + item.getReduceAmount();
                        operateItem.setCrAmount(item.getReduceAmount());
                    }
                    // 滞纳金减免叠加
                    if (item.getReduceOverdueAmount() != null) {
                        // TODO 检验减免金额是否超过本金
                        tempContent = tempContent + ",减免滞纳金：" + item.getReduceOverdueAmount();
                        operateItem.setCroAmount(item.getReduceOverdueAmount());
                    }
                    contentBuilder.append(tempContent);
                    items.add(operateItem);
                }
            }

            entity.setContent(contentBuilder.toString());
            operateItemService.saveBatch(items);
        }

        // 设置更新人
        String userId = userProvider.get().getUserId();
        entity.setCreatoruserid(userId);
        entity.setCreatortime(DateUtil.date());
        save(entity);
    }

    @Override
    public void operateBill(String id) {
        LambdaQueryWrapper<ZcBillOperateItemEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ZcBillOperateItemEntity::getParentId, id);
        List<ZcBillOperateItemEntity> operateList = operateItemService.list(queryWrapper);

        List<ZcBillItemEntity> updateItems = new ArrayList<>();
        for (ZcBillOperateItemEntity operateItem : operateList) {
            // 获取账单费用减免项
            ZcBillItemEntity billItem = billItemService.getById(operateItem.getBillItemId());

            // 减免本金
            if (operateItem.getCrAmount() != null) {
                BigDecimal billReduceAmount = billItem.getReduceAmount() == null ? BigDecimal.ZERO : billItem.getReduceAmount();
                // 费用项减免金额累加
                billItem.setReduceAmount(billReduceAmount.add(operateItem.getCrAmount()));
                // 实际应收减去此次减免的金额
                billItem.setRealAmount(billItem.getRealAmount().subtract(operateItem.getCrAmount()));
                // 待收 - 减免
                billItem.setPendAmount(billItem.getPendAmount().subtract(operateItem.getCrAmount()));
            }
            // 减免滞纳金
            if (operateItem.getCroAmount() != null) {
                BigDecimal billReduceOverdueAmount = billItem.getReduceOverdueAmount() == null ? BigDecimal.ZERO : billItem.getReduceOverdueAmount();
                billItem.setReduceOverdueAmount(billReduceOverdueAmount.add(operateItem.getCroAmount()));
                // 待收 - 减免
                billItem.setPendOverdueAmount(billItem.getPendOverdueAmount().subtract(operateItem.getCroAmount()));
            }
            // 退款本金
            if (operateItem.getPlanRefundAmount() != null) {
                // 账单费用详情表应退/待退金额累计
                BigDecimal billPlanRefundAmount = billItem.getPlanRefundAmount() == null ? BigDecimal.ZERO : billItem.getPlanRefundAmount();
                BigDecimal billPendRefundAmount = billItem.getPendRefundAmount() == null ? BigDecimal.ZERO : billItem.getPendRefundAmount();
                billItem.setPlanRefundAmount(billPlanRefundAmount.add(operateItem.getPlanRefundAmount()));
                billItem.setPendRefundAmount(billPendRefundAmount.add(operateItem.getPlanRefundAmount()));
            }

            updateItems.add(billItem);
        }

        // 更新账单价格
        billItemService.updateBatchById(updateItems);

        // 状态变更
        ZcBillOperateEntity operateEntity = getById(id);
        operateEntity.setFlowState(2);
        updateById(operateEntity);

    }

    @Override
    public void refundBill(ZcBillRefundForm form) {
        // 变更记录
        ZcBillOperateEntity entity = new ZcBillOperateEntity();
        entity.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
        // 减免账单
        entity.setParentId(form.getBillId());
        entity.setType(2);
        entity.setEventName("账单退款");

        // 生成流水号
        entity.setSerialNo(serialNumberService.getSerialNumber("R"));

        entity.setOperateDate(form.getRefundDate());
        entity.setReason(form.getReason());
        entity.setFilePath(form.getFile());

        // 获取减免费用项

        List<ZcBillRefundItemModel> refundItem = form.getRefundItem();
        if (CollUtil.isNotEmpty(refundItem)) {
            List<ZcBillItemEntity> updateItems = new ArrayList<>();
            List<ZcBillOperateItemEntity> items = new ArrayList<>();
            StringBuilder contentBuilder = new StringBuilder("");
            for (ZcBillRefundItemModel item : refundItem) {
                // 获取退款费用项
                ZcBillItemEntity billItem = billItemService.getById(item.getBillItemId());
                if (billItem != null) {
                    ZcBillOperateItemEntity operateItem = new ZcBillOperateItemEntity();
                    // 基础数据复制
                    operateItem.setId(IdUtil.getSnowflake(1, 1).nextIdStr());
                    operateItem.setParentId(entity.getId());
                    operateItem.setBillItemId(billItem.getId());
                    operateItem.setExpenseItem(billItem.getExpenseItem());

                    String tempContent = "|费用项:" + billItem.getExpenseItem();
                    // 计划退款金额叠加
                    if (item.getReturnAmount() != null) {
                        // TODO 检验退款金额是否超过本金
                        tempContent = tempContent + ",退款：" + item.getReturnAmount();
                        operateItem.setPlanRefundAmount(item.getReturnAmount());
                        operateItem.setPendRefundAmount(item.getReturnAmount());
                    }

                    contentBuilder.append(tempContent);
                    // 添加到更新列表
                    updateItems.add(billItem);
                    items.add(operateItem);
                }
            }

            entity.setContent(contentBuilder.toString());
            operateItemService.saveBatch(items);
        }

        // 设置更新人
        String userId = userProvider.get().getUserId();
        entity.setCreatoruserid(userId);
        entity.setCreatortime(DateUtil.date());
        save(entity);
    }

    @Override
    public ZcBillOperateDetailVo getBillOperateDetail(String id){

        ZcBillOperateDetailVo result = new ZcBillOperateDetailVo();

        // 主要信息
        ZcBillOperateMainVo mainInfo = this.baseMapper.getBillOperateMainDetail(id);
        result.setInfo(mainInfo);

        // 费用项信息
        LambdaQueryWrapper<ZcBillOperateItemEntity> itemQueryWrapper = new LambdaQueryWrapper<>();
        itemQueryWrapper.eq(ZcBillOperateItemEntity::getParentId,id);
        result.setDetails(operateItemService.list(itemQueryWrapper));

        // 交易费用变动记录

        return result;
    }

    @Override
    public IPage<ZcBillOperateMainVo> pageBillOperateList(ZcBillOperatePagination pagination) {
        // 创建查询的wrapper对象
        QueryWrapper<ZcBillOperateMainVo> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("1","1");
        if (StrUtil.isNotEmpty(pagination.getSerialNo())) {
            queryWrapper.eq("t1.`SERIAL_NO`", pagination.getSerialNo());
        }
        if (CollUtil.isNotEmpty(pagination.getProject())) {
            queryWrapper.in("t2.`PROJECT`", pagination.getProject());
        }
        if (StrUtil.isNotEmpty(pagination.getQueryBeginDate())) {
            queryWrapper.ge("t1.`OPERATE_DATE`", pagination.getQueryBeginDate());
        }
        if (StrUtil.isNotEmpty(pagination.getQueryEndDate())) {
            queryWrapper.le("t1.`OPERATE_DATE`", pagination.getQueryEndDate());
        }
        if (StrUtil.isNotEmpty(pagination.getBillNo())) {
            queryWrapper.eq("t2.`BILL_NO`", pagination.getBillNo());
        }
        if (StrUtil.isNotEmpty(pagination.getType())) {
            queryWrapper.eq("t1.`TYPE`", pagination.getType());
        }
        queryWrapper.orderByDesc("t1.`F_CreatorTime`");
        IPage<ZcBillOperateMainVo> result = this.baseMapper.getBillOperateList(new Page<ZcBillOperateMainVo>(pagination.getCurrentPage(), pagination.getPageSize()), queryWrapper);

        // 获取数据，然后汇总查询其金额相关数据
        List<ZcBillOperateMainVo> records = result.getRecords();
        if(CollUtil.isNotEmpty(records)){
            List<String> ids = records.stream().map(ZcBillOperateMainVo::getId).collect(Collectors.toList());
            // 对应操作主表下子表金额汇总
            Map<String, ZcBillOperateMainVo> map = this.baseMapper.getBillOperateSumAmount(ids).stream().collect(Collectors.toMap(ZcBillOperateMainVo::getId, Function.identity(), (key1, key2) -> key2));
            // 赋值
            records.forEach(item -> {
                ZcBillOperateMainVo amountInfo = map.get(item.getId());
                if(amountInfo != null) {
                    item.setTotalReduceAmount(amountInfo.getTotalReduceAmount());
                    item.setTotalReduceOverAmount(amountInfo.getTotalReduceOverAmount());
                    item.setTotalPlanRefundAmount(amountInfo.getTotalPlanRefundAmount());
                    item.setTotalPendRefundAmount(amountInfo.getTotalPendRefundAmount());
                    item.setTotalRefundAmount(amountInfo.getTotalRefundAmount());
                }
            });

        }

        return result;
    }

}
